package com.zj;

import org.apache.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;


/**
 * @program: concurrent
 * @description: 多线程下载
 * @author: zy
 * @create: 2022-01-20 09:14
 */
public class XunLei {
    /*
  https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload1530.exe
得到这个待下载文件的大小，并在本地创建空文件。
文件名：　　时间
后缀名：　　　原文件的后缀名．　
目录：  用户目录下．　　　C:\Users\zy　　　　　　Ｓｙｓｔｅｍ
   */

    private static final Logger logger = Logger.getLogger(XunLei.class);  //日志对象

   // volatile static int total=0;   // AtomicLong
   static AtomicLong total=new AtomicLong(0L);

   static class LengthNotify implements Notify{
        @Override
        public  void notifyResult(long length) {
           // synchronized( this) {
               // total += length;
              total.addAndGet(    length );  //AtomicLong中 addAndGet() 方法  原子累加操作
           // }
            System.out.println(   "下载了:"+total.get()+"字节" );
            //System.out.println(   "总共下载了:"+total+"字节" );
        }
    }

    public static void main(String[] args) throws IOException {
       URL a=new URL("http://www.baidu.com"); //创建一个



        String url = "https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload1530.exe";  // 2186968字节
//        String url="http://dl.baofeng.com/baofeng5/bf5_new.exe";                // 106617136
       // String url="http://www.hostbuf.com/downloads/finalshell_install.exe";     //  87895209字节   特别慢

        long fileSize= getDownLoadFileSize(   url );  //获取待下载文件大小
        logger.info(   "待下载的文件:"+ url+"的大小为:"+fileSize + "字节");
        String newFileName= genFileName( url );//根据url地址生成新的保存后的文件名.

        String newFileAddress=getNewFileAddress(   newFileName); //新文件的物理位置
        RandomAccessFile raf = new RandomAccessFile( newFileAddress   , "rw");  //创建随机访问文件对象
        raf.setLength(fileSize);  //指定文件大小
        raf.close();
        logger.info("文件已经创建," + raf.getFD().toString());

        int threadSize=Runtime.getRuntime().availableProcessors();   //线程数
       // int threadSize=4;
        long sizePerThread=getSizePerThread(    fileSize, threadSize ); //每个线程要下载的文件大小

        LengthNotify lnt=new LengthNotify();   //由主线程产生的通知对象，负责累加 每个子线程下载的数据量.
        //创建线程组.
        //读取.tmp文件，得到每个线程已经下载的文件量
        for( int i=0;i<threadSize;i++){
            DownLoadTask task=new DownLoadTask(  i, fileSize,threadSize,sizePerThread,url, newFileAddress,lnt  );
            Thread t=new Thread(  task  );  //加入线程组
            t.start();
        }
    }

    /**
     * 根据文件大小及线程数计算每个线程要下载的字节数
     * @param fileSize
     * @param threadSize
     * @return
     */
    private static long getSizePerThread(   long fileSize, int threadSize){
        // 101字节
        // 5
        // 101/5+1
        //    21*4=84字节  -  21*5=105     4 字节.    超时关闭.
        return fileSize%threadSize==0? fileSize/threadSize: fileSize/threadSize+1;
    }


    /**
     * 新文件的物理位置
     * @param newFileName
     * @return
     */
    private static String getNewFileAddress(   String newFileName ){
        String userhome = System.getProperty("user.home");
        return userhome + File.separator + newFileName;
    }

    /**
     * 根据url地址生成新的保存后的文件名.
     * @param url
     * @return
     */
    private static String genFileName(   String url){
        //文件名
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String fileName = sdf.format(d);
        //后缀名
        String suffix = url.substring(url.lastIndexOf("."));
        String newFileName = fileName + suffix;
        return newFileName;
    }


    /**
     * 获取待下载的文件大小
     * @param url
     * @return
     */
    private static long getDownLoadFileSize(String url) {
        long fileSize = 0;
        try {
            URL u = new URL(url);
            HttpURLConnection con = (HttpURLConnection) u.openConnection();
            //关键:   请求的方法:  HEAD
            con.setRequestMethod("HEAD");
            con.setConnectTimeout(3000);   //超时
            con.connect();

            //scrapy

//            new Socket();
//            s.getOutputStream ();
//            out.println("GET /xxx HTTP/1.1");
////
////            if( 代理.open() ){
////                sendByProxy(  out );
////            }
////            if( useragent.open() ){
////                useragent(  xxx )
////            }
//
//            List<功能接口> list=new ArrayList<功能 接口>();
//            读取xml配置文件，看配置了多少个功能
//                    list.add(   new  功能接口的实现 );
//
//            for(  功能接口的实现 a:list){
//                a.doxxx( out );
//            }
//

            //  Socket s=new Socket(  "https://pm.myapp.com", 80);
            //   "HEAD /invc/xfspeed/qqpcmgr/download/QQPCDownload1530.exe HTTP/1.1\r\n\r\n"
            //获取结果
            fileSize = con.getContentLength();
        } catch (Exception ex) {
            ex.printStackTrace();
            logger.error(ex.getMessage());
        }
        return fileSize;
    }
}


interface Notify{
    public void notifyResult(  long length );
}

